﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Globalization;
using System.Collections;
using System.Collections.Concurrent;

namespace SernaJson
{
    internal static class ObjectsFactory
    {
        //static ReaderWriterLockSlim _sync = new ReaderWriterLockSlim();
        //static Dictionary<string, ObjectDefinition> dObjs = new Dictionary<string, ObjectDefinition>();
        static ConcurrentDictionary<string, ObjectDefinition> dObjs = new ConcurrentDictionary<string, ObjectDefinition>();

        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="obj"></param>
        ///// <returns></returns>
        public static ObjectDefinition GetObjectDefinition(object obj)
        {
           // return GetObjectDefinition(obj.GetType());

            ObjectDefinition od = null;

            if (!dObjs.TryGetValue(obj.ToString(), out od))
            {
                od = ParseObject(obj.GetType());
                dObjs[obj.ToString()] = od;
            }
            return od;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static ObjectDefinition GetObjectDefinition(Type objType)
        {
            ObjectDefinition od = null;

           // Type t = objType;
            //string strType = t.ToString();
            string strType = objType.FullName;

            if (!dObjs.TryGetValue(strType, out od))
            {
                od = ParseObject(objType);
                dObjs[strType] = od;

                //if (!dObjs.TryGetValue(strType, out od))    //Recheck after entering the write locks
                //{
                //    od = ParseObject(objType);
                //    dObjs[strType] = od;
                //}
            }

            //_sync.EnterUpgradeableReadLock();
            //try
            //{
            //    Type t = objType;
            //    string strType = t.ToString();

            //    if (!dObjs.TryGetValue(strType, out od))
            //    {
            //        _sync.EnterWriteLock();
            //        try
            //        {
            //            if (!dObjs.TryGetValue(strType, out od))    //Recheck after entering the write locks
            //            {
            //                od = ParseObject(t);
            //                dObjs[strType] = od;
            //            }
            //        }
            //        finally
            //        {
            //            _sync.ExitWriteLock();
            //        }
            //    }
            //}
            //finally
            //{
            //    _sync.ExitUpgradeableReadLock();
            //}

            return od;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        static bool IsClassAnonymous(Type type)
        {
            if (type.IsGenericType)
            {
                var d = type.GetGenericTypeDefinition();
                if (d.IsClass && d.IsSealed && d.Attributes.HasFlag(TypeAttributes.NotPublic))
                {
                    var attributes = d.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), false);
                    if (attributes != null && attributes.Length > 0)
                    {
                        //We have an anonymous type
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="xstr"></param>
        /// <returns></returns>
        static int CustomStringToInt32(string xstr)
        {
            int y = 0;

            for (int ii = 0; ii < xstr.Length; ii++)
            {
                y = y * 10 + (xstr[ii] - '0');
            }
           
            return y;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="attribute"></param>
        /// <returns></returns>
        static Tuple<int[],int> SplitArrayAttribute(string attribute)
        {
            StringBuilder sb = new StringBuilder();
            int[] dim = new int[10];
            int i = -1;
            foreach (var c in attribute)
            {
                if (c == ' ' && sb.Length>0)
                {
                    i++;
                    dim[i] = CustomStringToInt32(sb.ToString());
                    sb.Clear();
                }
                else
                {
                    sb.Append(c);
                }
            }

            if (sb.Length > 0)  //Las element
            {
                i++;
                dim[i] = CustomStringToInt32(sb.ToString());
                sb.Clear();
            }
            return new Tuple<int[], int>(dim, i);
        }

       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="attribute"></param>
        /// <param name="arrayType"></param>
        /// <returns></returns>
        public static object GetArrayInstance(string attribute, Type arrayType)
        {
            string[] dims = attribute.Split(' ');
           //var res = SplitArrayAttribute(attribute);

            switch (dims.Length)
            {
                case 1:
                    return ExpressionBasedReflection.GetInstanceCreatorForArrays1D()(arrayType, CustomStringToInt32(dims[0]) + 1);
                case 2:
                    return ExpressionBasedReflection.GetInstanceCreatorForArrays2D()(arrayType, CustomStringToInt32(dims[0]) + 1, CustomStringToInt32(dims[1]) + 1);
                case 3:
                    return ExpressionBasedReflection.GetInstanceCreatorForArrays3D()(arrayType, CustomStringToInt32(dims[0]) + 1, CustomStringToInt32(dims[1]) + 1, CustomStringToInt32(dims[2]) + 1);
            }

            throw new Exception("GetArrayInstance Unsupported array rank");
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        static ObjectDefinition ParseObject(Type t)
        {
            ObjectDefinition obj = new ObjectDefinition();
            //obj.ObjectName = t.FullName;
            //obj.ObjectType = t;

            //Getting instance creator
            if (!t.IsArray)
            {
                if (!IsClassAnonymous(t))
                    obj.InstanceCreator = ExpressionBasedReflection.GetInstanceCreator(t);
            }           

            if(t.IsArray)
            {                
                obj.Description = ObjectDefinition.eObjectDescription.Array;
                //obj.Descriptor = ObjectDefinition.eDescriptor.SERIALIZED_WITHOUT_KEY;
                obj.GenericArgument1 = t.GetElementType();
                obj.valueTypeFromStringConverter = ObjectsFactory.GetFromStringConverterForStaticType(obj.GenericArgument1);
                obj.valueTypeToStringConverter = ObjectsFactory.GetToStringConverterForStaticType(obj.GenericArgument1);             
                return obj;
            }

           // ConcurrentDictionary
            //Special cases (IDict, Ilist,Iset, arrays)
            if (t.GetInterface(typeof(IDictionary<,>).Name) != null)
            {
                obj.Description = ObjectDefinition.eObjectDescription.Dictionary;                

                Type[] arguments = t.GetGenericArguments();
                obj.GenericArgument1 = arguments[0];
                obj.GenericArgument2 = arguments[1];

                //For the Dictionary
                obj.Dictionary_AddElement = ExpressionBasedReflection.SetterMethodAddOfGenericDictionary(t);

                //If key or value are Complex Types, correspondent converter will stay null
                obj.keyTypeFromStringConverter = ObjectsFactory.GetFromStringConverterForStaticType(obj.GenericArgument1);

                if(obj.keyTypeFromStringConverter == null)
                    throw new Exception("WSN_NetCode.ReflectionFactory.ObjectsFactory.ParseObject Dictionary key can't get type converter");

                obj.keyTypeToStringConverter = ObjectsFactory.GetToStringConverterForStaticType(obj.GenericArgument1);


                obj.valueTypeFromStringConverter = ObjectsFactory.GetFromStringConverterForStaticType(obj.GenericArgument2);
                obj.valueTypeToStringConverter = ObjectsFactory.GetToStringConverterForStaticType(obj.GenericArgument2);
                //Don't go further, we are not interested in this specific type properties and methods
                return obj;
            }
            else if (t.GetInterface(typeof(IDictionary).Name) != null)
            {
                throw new Exception("WSN_NetCode.ReflectionFactory.ObjectsFactory.ParseObject Unsupported type (non generic Dictionary)");
            }            

            if (t.GetInterface(typeof(IList<>).Name) != null)
            {
                obj.Description = ObjectDefinition.eObjectDescription.List;
                //obj.Descriptor = ObjectDefinition.eDescriptor.SERIALIZED_WITHOUT_KEY;

                Type[] arguments = t.GetGenericArguments();
                obj.GenericArgument1 = arguments[0];

                //For the List
                obj.List_AddElement = ExpressionBasedReflection.SetterMethodAddOfGenericList(t);
                //If key or value are Complex Types, correspondent converter will stay null          
                obj.valueTypeFromStringConverter = ObjectsFactory.GetFromStringConverterForStaticType(obj.GenericArgument1);
                obj.valueTypeToStringConverter = ObjectsFactory.GetToStringConverterForStaticType(obj.GenericArgument1);
                //Don't go further, we are not interested in this specific type properties and methods
                return obj;
            }
            else if (t.GetInterface(typeof(IList).Name) != null)
            {
                throw new Exception("WSN_NetCode.ReflectionFactory.ObjectsFactory.ParseObject Unsupported type (non generic List)");
            }


            if (t.GetInterface(typeof(ISet<>).Name) != null)
            {

                obj.Description = ObjectDefinition.eObjectDescription.HashSet;
                //obj.Descriptor = ObjectDefinition.eDescriptor.SERIALIZED_WITHOUT_KEY;

                Type[] arguments = t.GetGenericArguments();
                obj.GenericArgument1 = arguments[0];               

                //For the List
                obj.HashSet_AddElement = ExpressionBasedReflection.SetterMethodAddOfGenericHashSet(t);
                //If key or value are Complex Types, correspondent converter will stay null          
                obj.valueTypeFromStringConverter = ObjectsFactory.GetFromStringConverterForStaticType(obj.GenericArgument1);
                obj.valueTypeToStringConverter = ObjectsFactory.GetToStringConverterForStaticType(obj.GenericArgument1);
                //Don't go further, we are not interested in this specific type properties and methods
                return obj;
            }


            
            

            obj.Description = ObjectDefinition.eObjectDescription.CustomClass;

            PropertyDefinition pd = null;

            foreach (FieldInfo field in t.GetFields())
            {
                if (field.FieldType == typeof(object))
                    continue;

                if (field.FieldType.IsArray && field.FieldType != typeof(byte[]))
                {                    
                    obj.Properties.Add(field.Name, new PropertyDefinition
                    {
                        Getter = ExpressionBasedReflection.GetFieldGetter(field),
                        Setter = ExpressionBasedReflection.GetFieldSetter(field),
                        Type = field.FieldType,
                        Mode = PropertyDefinition.eProperty.Array
                        //Type = field.FieldType,
                        //Mode = PropertyDefinition.eProperty.Array,
                        //TypeConverterFromString = GetTypeConverterFromString(field.FieldType.GetElementType()),
                        //TypeConverterToString = GetTypeConverterToString(field.FieldType.GetElementType()),
                        //ArrayRank = field.FieldType.GetArrayRank()
                    });
                }              
                else
                {
                    obj.Properties.Add(field.Name, new PropertyDefinition
                    {
                        Getter = ExpressionBasedReflection.GetFieldGetter(field),
                        Setter = ExpressionBasedReflection.GetFieldSetter(field),
                        Type = field.FieldType,
                        Mode = PropertyDefinition.eProperty.Field,
                        TypeConverterFromString = GetTypeConverterFromString(field.FieldType),
                        TypeConverterToString = GetTypeConverterToString(field.FieldType)
                    });
                }
            }
                        
            foreach (PropertyInfo prop in t.GetProperties().Where(r=>r.CanRead && r.CanWrite))
            {
                if (prop.PropertyType == typeof(object))
                    continue;

                if (prop.PropertyType.IsArray && prop.PropertyType != typeof(byte[]))
                {
                    pd = new PropertyDefinition()
                    {
                        Getter = ExpressionBasedReflection.GetPropertyGetter(prop),
                        Setter = ExpressionBasedReflection.GetPropertySetter(prop),
                        Type = prop.PropertyType,
                        Mode = PropertyDefinition.eProperty.Array,
                        //TypeConverterFromString = GetTypeConverterFromString(prop.PropertyType.GetElementType()),
                        //TypeConverterToString = GetTypeConverterToString(prop.PropertyType.GetElementType()),                                                
                    };
                }
                else
                {
                    pd = new PropertyDefinition()
                    {
                        Type = prop.PropertyType,
                        Mode = PropertyDefinition.eProperty.Property,
                        TypeConverterFromString = GetTypeConverterFromString(prop.PropertyType),
                        TypeConverterToString = GetTypeConverterToString(prop.PropertyType),
                        Getter = ExpressionBasedReflection.GetPropertyGetter(prop),
                        Setter = ExpressionBasedReflection.GetPropertySetter(prop)
                    };
                }
                obj.Properties.Add(prop.Name, pd);
               
            }

            return obj;

        }//eom

      
        #region "Type Converter ToString"


        /// <summary>
        /// Key is TypeFullName, Value is converter to string for static types
        /// </summary>
        static Dictionary<string, Action<StringBuilder, object, SerializationSettings>> dStaticTypeConverters = new Dictionary<string, Action<StringBuilder, object, SerializationSettings>>();
        static ReaderWriterLockSlim _sync_dStaticTypeConverters = new ReaderWriterLockSlim();
//        static System.Collections.Concurrent.ConcurrentDictionary<string, Action<StringBuilder, object, SerializationSettings>>


        /// <summary>
        /// !!!!!!!!!!!!!!!!!!!   here it's possible to add Dynamic DateTime converter
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static Action<StringBuilder, object, SerializationSettings> GetToStringConverterForStaticType(Type t)
        {
            Action<StringBuilder, object, SerializationSettings> res = null;

            _sync_dStaticTypeConverters.EnterUpgradeableReadLock();
            try
            {
               
                string strType = t.ToString();

                if (!dStaticTypeConverters.TryGetValue(strType, out res))
                {
                    _sync_dStaticTypeConverters.EnterWriteLock();
                    try
                    {
                        if (!dStaticTypeConverters.TryGetValue(strType, out res))
                        {
                            res = GetTypeConverterToString(t);
                            dStaticTypeConverters[strType] = res;
                        }
                    }
                    finally
                    {
                        _sync_dStaticTypeConverters.ExitWriteLock();
                    }
                }
            }
            finally
            {
                _sync_dStaticTypeConverters.ExitUpgradeableReadLock();
            }

            return res;
        }


        //public static unsafe string WritingStringUnsafe1(string s,StringBuilder sb, SerializationSettings ss)
        //{
        //    int len = s.Length;
        //    char* newChars = stackalloc char[len];
        //    char* currentChar = newChars;

        //    for (int i = 0; i < len; ++i)
        //    {
        //        char c = s[i];
        //        switch (c)
        //        {
        //            case '\r':
        //            case '\n':
        //            case '\t':
        //                continue;
        //            default:
        //                *currentChar++ = c;
        //                break;
        //        }
        //    }
        //    return new string(newChars, 0, (int)(currentChar - newChars));
        //}


        //public static unsafe void WritingStringUnsafe(string str, StringBuilder sb, SerializationSettings ss)
        public static unsafe void WritingStringUnsafe(StringBuilder sb, string str, SerializationSettings ss)
        {
            //sb.Append(str);
            //return;
           // string str = (string)ostr;
            //Control chars
            //https://msdn.microsoft.com/en-us/library/18zw7440%28v=vs.110%29.aspx

            fixed (char* pfixed = str)
            {
                char bs = '\\';

                char* newChars = stackalloc char[str.Length * 6];                
                char* currentChar = newChars;
                int i = 0;

                *currentChar++ = ss.Framing;
                i++;

                for (char* p = pfixed; *p != 0; p++)
                {
                    #region "Moptex"
                    ////if (*p < '\u0020' || (*p > '\u007E' && *p < '\u00A0'))
                    ////if (*p < '\u0020' || (*p > '\u007E' && *p < '\u00A0') || *p == '\u0022' || *p == '\u005c' || *p == '\u002F' || *p == '\u0027')
                    //if (*p < '\u0020')
                    //{
                    //    switch (*p)
                    //    {
                    //        case '\t':
                    //        case '\r':
                    //        case '\n':
                    //        case '\b':
                    //        case '\f':
                    //            *currentChar++ = bs;
                    //            *currentChar++ = *p;
                    //            i += 2;
                    //            break;
                    //        default:
                    //            //"\u{0:X4}
                    //            break;
                    //    }
                    //}
                    ////else if (*p == '\u0022')
                    ////{

                    ////}
                    ////else if (*p == '\u005c')
                    ////{

                    ////}
                    ////else if (*p == '\u002F')
                    ////{

                    ////}
                    ////else if (*p == '\u0027')
                    ////{

                    ////}
                    ////else if (*p == '\u0022')
                    ////{

                    ////}
                    //else if (*p > '\u007E' && *p < '\u00A0')
                    //{
                    //    //"\u{0:X4}
                    //}
                    ////if (*p == 34 || *p == 92 || *p == 47 || *p == 39)
                    ////{

                    ////}
                    //else
                    //{
                    //    //*currentChar++ = *p;
                    //    //i++;

                    //    switch (*p)
                    //    {
                    //        case '\u0022'://'\"':
                    //        case '\u005c'://'\\':
                    //        case '\u002F'://'/':
                    //            *currentChar++ = bs;
                    //            *currentChar++ = *p;
                    //            i += 2;
                    //            break;
                    //        case '\u0027'://'\'':
                    //            if (*p == ss.Framing)
                    //            {
                    //                *currentChar++ = bs;
                    //                *currentChar++ = *p;
                    //                i += 2;
                    //            }
                    //            else
                    //            {
                    //                *currentChar++ = *p;
                    //                i++;
                    //            }
                    //            break;
                    //        default:
                    //            *currentChar++ = *p;
                    //            i++;
                    //            break;
                    //    }


                    //}


                    //if (*p < 32 || (*p > 126 && *p < 160))
                    //{
                    //    switch (*p)
                    //    {
                    //        case '\t':
                    //        case '\r':
                    //        case '\n':
                    //        case '\b':
                    //        case '\f':
                    //                *currentChar++ = bs;
                    //                *currentChar++ = *p;
                    //                i += 2;
                    //            break;
                    //        default:
                    //            //"\u{0:X4}
                    //            break;
                    //    }
                    //}
                    ////if (*p == 34 || *p == 92 || *p == 47 || *p == 39)
                    ////{

                    ////}
                    //else
                    //{
                    //    //*currentChar++ = *p;
                    //    //i++;
                    //    switch (*p)
                    //    {
                    //        case '\"':
                    //        case '\\':
                    //        case '/':
                    //            *currentChar++ = bs;
                    //            *currentChar++ = *p;
                    //            i += 2;
                    //            break;
                    //        case '\'':
                    //            if (*p == ss.Framing)
                    //            {
                    //                *currentChar++ = bs;
                    //                *currentChar++ = *p;
                    //                i += 2;
                    //            }
                    //            else
                    //            {
                    //                *currentChar++ = *p;
                    //                i++;
                    //            }
                    //            break;
                    //        default:
                    //            *currentChar++ = *p;
                    //            i++;
                    //            break;
                    //    }                     


                    //}
                    #endregion
                    
                    switch (*p)
                    {

                        case '\t':
                        case '\r':
                        case '\n':
                        case '\b':
                        case '\f':
                        case '\"':
                        case '\\':
                        case '/':
                            *currentChar++ = bs;
                            *currentChar++ = *p;
                            i += 2;
                            break;
                        case '\'':
                            if (*p == ss.Framing)
                            {
                                *currentChar++ = bs;
                                *currentChar++ = *p;
                                i += 2;
                            }
                            else
                            {
                                *currentChar++ = *p;
                                i++;
                            }
                            break;

                        case '\u0000':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '0';
                            *currentChar++ = '0';
                            break;
                        case '\u0001':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '0';
                            *currentChar++ = '1';
                            break;
                        case '\u0002':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '0';
                            *currentChar++ = '2';
                            break;
                        case '\u0003':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '0';
                            *currentChar++ = '3';
                            break;
                        case '\u0004':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '0';
                            *currentChar++ = '4';
                            break;
                        case '\u0005':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '0';
                            *currentChar++ = '5';
                            break;
                        case '\u0006':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '0';
                            *currentChar++ = '6';
                            break;
                        case '\u0007':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '0';
                            *currentChar++ = '7';
                            break;
                        case '\u000B':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '0';
                            *currentChar++ = 'B';
                            break;
                        case '\u000E':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '0';
                            *currentChar++ = 'E';
                            break;
                        case '\u000F':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '0';
                            *currentChar++ = 'F';
                            break;
                        case '\u0010':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = '0';
                            break;
                        case '\u0011':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = '1';
                            break;
                        case '\u0012':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = '2';
                            break;
                        case '\u0013':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = '3';
                            break;
                        case '\u0014':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = '4';
                            break;
                        case '\u0015':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = '5';
                            break;
                        case '\u0016':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = '6';
                            break;
                        case '\u0017':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = '7';
                            break;
                        case '\u0018':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = '8';
                            break;
                        case '\u0019':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = '9';
                            break;
                        case '\u001A':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = 'A';
                            break;
                        case '\u001B':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = 'B';
                            break;
                        case '\u001C':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = 'C';
                            break;
                        case '\u001D':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = 'D';
                            break;
                        case '\u001E':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = 'E';
                            break;
                        case '\u001F':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '1';
                            *currentChar++ = 'F';
                            break;

                        case '\u007F':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '7';
                            *currentChar++ = 'F';
                            break;
                        case '\u0080':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = '0';
                            break;
                        case '\u0081':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = '1';
                            break;
                        case '\u0082':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = '2';
                            break;
                        case '\u0083':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = '3';
                            break;
                        case '\u0084':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = '4';
                            break;
                        case '\u0085':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = '5';
                            break;
                        case '\u0086':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = '6';
                            break;
                        case '\u0087':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = '7';
                            break;
                        case '\u0088':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = '8';
                            break;
                        case '\u0089':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = '9';
                            break;
                        case '\u008A':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = 'A';
                            break;
                        case '\u008B':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = 'B';
                            break;
                        case '\u008C':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = 'C';
                            break;
                        case '\u008D':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = 'D';
                            break;
                        case '\u008E':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = 'E';
                            break;
                        case '\u008F':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '8';
                            *currentChar++ = 'F';
                            break;
                        case '\u0090':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = '0';
                            break;
                        case '\u0091':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = '9';
                            break;
                        case '\u0092':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = '2';
                            break;
                        case '\u0093':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = '3';
                            break;
                        case '\u0094':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = '4';
                            break;
                        case '\u0095':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = '5';
                            break;
                        case '\u0096':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = '6';
                            break;
                        case '\u0097':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = '7';
                            break;
                        case '\u0098':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = '8';
                            break;
                        case '\u0099':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = '9';
                            break;
                        case '\u009A':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = 'A';
                            break;
                        case '\u009B':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = 'B';
                            break;
                        case '\u009C':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = 'C';
                            break;
                        case '\u009D':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = 'D';
                            break;
                        case '\u009E':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = 'E';
                            break;
                        case '\u009F':
                            i += 6; *currentChar++ = bs; *currentChar++ = 'u'; *currentChar++ = '0'; *currentChar++ = '0'; *currentChar++ = '9';
                            *currentChar++ = 'F';
                            break;

                        default:
                            *currentChar++ = *p;
                            i++;
                            break;
                    }

                  

                }

                *currentChar++ = ss.Framing;
                i++;
                
                sb.Append(new string(newChars, 0, i));
                
            }
        }








        //public static unsafe void WritingStringUnsafe(string str, StringBuilder sb, SerializationSettings ss)
        //{
        //    fixed (char* pfixed = str)
        //    {
        //        char bs = '\\';
        //        //char* newChars = stackalloc char[str.Length*6];
        //        //char* currentChar = newChars;
        //        //int i = 0;
        //        //char bs = '\\';

        //        //*currentChar++ = ss.Framing;
        //        //i++;
        //        sb.Append(ss.Framing);

        //        for (char* p = pfixed; *p != 0; p++)
        //        {
        //            //*currentChar++ = *p;

        //            switch (*p)
        //            {

        //                case '\t':
        //                case '\r':
        //                case '\n':
        //                case '\b':
        //                case '\f':
        //                case '\"':
        //                case '\\':
        //                case '/':
        //                    sb.Append(bs);
        //                    sb.Append(*p);
        //                    //*currentChar++ = bs;                            
        //                    //*currentChar++ = *p;
        //                    //i += 2;
        //                    break;
        //                case '\'':
        //                    if (*p == ss.Framing)
        //                    {
        //                        sb.Append(bs);
        //                        sb.Append(*p);

        //                        //*currentChar++ = bs;
        //                        //*currentChar++ = *p;
        //                        //i += 2;
        //                    }
        //                    else
        //                    {
        //                        sb.Append(*p);
        //                        //*currentChar++ = *p;
        //                        //i++;
        //                    }
        //                    break;
        //                case '\u0000': sb.Append(@"\u0000"); break;
        //                case '\u0001': sb.Append(@"\u0001"); break;
        //                case '\u0002': sb.Append(@"\u0002"); break;
        //                case '\u0003': sb.Append(@"\u0003"); break;
        //                case '\u0004': sb.Append(@"\u0004"); break;
        //                case '\u0005': sb.Append(@"\u0005"); break;
        //                case '\u0006': sb.Append(@"\u0006"); break;
        //                case '\u0007': sb.Append(@"\u0007"); break;
        //                case '\u000B': sb.Append(@"\u000B"); break;
        //                case '\u000E': sb.Append(@"\u000E"); break;
        //                case '\u000F': sb.Append(@"\u000F"); break;
        //                case '\u0010': sb.Append(@"\u0010"); break;
        //                case '\u0011': sb.Append(@"\u0011"); break;
        //                case '\u0012': sb.Append(@"\u0012"); break;
        //                case '\u0013': sb.Append(@"\u0013"); break;
        //                case '\u0014': sb.Append(@"\u0014"); break;
        //                case '\u0015': sb.Append(@"\u0015"); break;
        //                case '\u0016': sb.Append(@"\u0016"); break;
        //                case '\u0017': sb.Append(@"\u0017"); break;
        //                case '\u0018': sb.Append(@"\u0018"); break;
        //                case '\u0019': sb.Append(@"\u0019"); break;
        //                case '\u001A': sb.Append(@"\u001A"); break;
        //                case '\u001B': sb.Append(@"\u001B"); break;
        //                case '\u001C': sb.Append(@"\u001C"); break;
        //                case '\u001D': sb.Append(@"\u001D"); break;
        //                case '\u001E': sb.Append(@"\u001E"); break;
        //                case '\u001F': sb.Append(@"\u001F"); break;
        //                default:
        //                    sb.Append(*p);
        //                    //*currentChar++ = *p;
        //                    //i++;
        //                    break;
        //            }


        //        }

        //        //*currentChar++ = ss.Framing;
        //        //i++;               
        //        //sb.Append(new string(newChars, 0, i));
        //        sb.Append(ss.Framing);
        //    }
        //}

        
        //public static unsafe void WritingStringUnsafe(string str, StringBuilder sb, SerializationSettings ss)
        //{
        //    fixed (char* pfixed = str)
        //    {
        //        sb.Append(ss.Framing);
        //        for (char* p = pfixed; *p != 0; p++)
        //        {                   
        //            switch (*p)
        //            {

        //                case '\t': sb.Append("\\t"); break;
        //                case '\r': sb.Append("\\r"); break;
        //                case '\n': sb.Append("\\n"); break;
        //                case '\b': sb.Append("\\b"); break;
        //                case '\f': sb.Append("\\f"); break;
        //                case '\'':
        //                    if (*p == ss.Framing)
        //                        sb.Append("\\\'");
        //                    else
        //                        sb.Append(*p);
        //                    break;
        //                case '\"': sb.Append("\\\""); break;
        //                case '\\': sb.Append("\\\\"); break;
        //                case '/': sb.Append("\\/"); break;
        //                case '\u0000': sb.Append(@"\u0000"); break;
        //                case '\u0001': sb.Append(@"\u0001"); break;
        //                case '\u0002': sb.Append(@"\u0002"); break;
        //                case '\u0003': sb.Append(@"\u0003"); break;
        //                case '\u0004': sb.Append(@"\u0004"); break;
        //                case '\u0005': sb.Append(@"\u0005"); break;
        //                case '\u0006': sb.Append(@"\u0006"); break;
        //                case '\u0007': sb.Append(@"\u0007"); break;
        //                case '\u000B': sb.Append(@"\u000B"); break;
        //                case '\u000E': sb.Append(@"\u000E"); break;
        //                case '\u000F': sb.Append(@"\u000F"); break;
        //                case '\u0010': sb.Append(@"\u0010"); break;
        //                case '\u0011': sb.Append(@"\u0011"); break;
        //                case '\u0012': sb.Append(@"\u0012"); break;
        //                case '\u0013': sb.Append(@"\u0013"); break;
        //                case '\u0014': sb.Append(@"\u0014"); break;
        //                case '\u0015': sb.Append(@"\u0015"); break;
        //                case '\u0016': sb.Append(@"\u0016"); break;
        //                case '\u0017': sb.Append(@"\u0017"); break;
        //                case '\u0018': sb.Append(@"\u0018"); break;
        //                case '\u0019': sb.Append(@"\u0019"); break;
        //                case '\u001A': sb.Append(@"\u001A"); break;
        //                case '\u001B': sb.Append(@"\u001B"); break;
        //                case '\u001C': sb.Append(@"\u001C"); break;
        //                case '\u001D': sb.Append(@"\u001D"); break;
        //                case '\u001E': sb.Append(@"\u001E"); break;
        //                case '\u001F': sb.Append(@"\u001F"); break;
        //                default:
        //                    sb.Append(*p);
        //                    break;
        //            }


        //        }
        //        sb.Append(ss.Framing);
        //    }
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="t"></param>
        public static Action<StringBuilder, object, SerializationSettings> GetTypeConverterToString(Type t)
        {

            //Action<string, StringBuilder, SerializationSettings> WritingString = (stre, sb, ss) =>
            //{
            //    sb.Append(ss.Framing);

            //    //for (int i = 0; i < stre.Length; ++i)
            //    //    sb.Append(stre[i]);

            //    //foreach (var c in (System.String)stre)
            //    //{
            //    //   sb.Append(c);


            //    //    ////Thoughts from http://fastjson.codeplex.com/SourceControl/latest#fastJSON/JsonSerializer.cs
            //    //    ////Thoughts from https://github.com/ServiceStack/ServiceStack.Text/blob/master/src/ServiceStack.Text/Json/JsonTypeSerializer.cs

            //    //    //switch (c)
            //    //    //{
            //    //    //    case '\t': sb.Append("\\t"); break;
            //    //    //    case '\r': sb.Append("\\r"); break;
            //    //    //    case '\n': sb.Append("\\n"); break;
            //    //    //    case '\b': sb.Append("\\b"); break;
            //    //    //    case '\f': sb.Append("\\f"); break;
            //    //    //    case '\'':
            //    //    //        if (c == ss.Framing)
            //    //    //            sb.Append("\\\'");
            //    //    //        else
            //    //    //            sb.Append(c);
            //    //    //        break;
            //    //    //    case '\"': sb.Append("\\\""); break;
            //    //    //    case '\\': sb.Append("\\\\"); break;
            //    //    //    case '/': sb.Append("\\/"); break;
            //    //    //    default:

            //    //    //        sb.Append(c);

            //    //    //        //if (char.IsControl(c))
            //    //    //        //{
            //    //    //        //    sb.Append("\\u");
            //    //    //        //    sb.Append(((int)c).ToString("X4", NumberFormatInfo.InvariantInfo));
            //    //    //        //}
            //    //    //        //else
            //    //    //        //{
            //    //    //        //    sb.Append(c);
            //    //    //        //}

            //    //    //        //if (c >= 32 && c <= 126)
            //    //    //        //    sb.Append(c);
            //    //    //        //else if (char.IsControl(c))
            //    //    //        //{
            //    //    //        //    sb.Append("\\u");
            //    //    //        //    sb.Append(((int)c).ToString("X4", NumberFormatInfo.InvariantInfo));
            //    //    //        //}
            //    //    //        //else
            //    //    //        //    sb.Append(c);

            //    //    //        break;
            //    //    //}
            //    //}
            //    sb.Append(ss.Framing);
            //};

            


            Action<object, StringBuilder, SerializationSettings> WritingDateTime = (p1, sb, ss) =>
            {

                DateTime dt = (System.DateTime)p1;
                switch (ss.DateTimeFormat)
                {
                    case SerializationSettings.eDateTimeFormat.UnixTime:
                        sb.Append(dt.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, 0, dt.Kind)).TotalSeconds * 1000);
                        break;
                    case SerializationSettings.eDateTimeFormat.ISO8601:
                        sb.Append(ss.Framing);
                        if (dt.Kind == DateTimeKind.Utc)
                            sb.Append(dt.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"));
                        else
                            sb.Append(dt.ToString("yyyy-MM-ddTHH:mm:ss.fff"));
                        sb.Append(ss.Framing);
                        break;
                    case SerializationSettings.eDateTimeFormat.JavaScriptSerializer:
                        //\/Date(1293034567877)\/
                        sb.Append(ss.Framing);
                        sb.Append("\\/Date(");
                        sb.Append(dt.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, 0, dt.Kind)).TotalSeconds * 1000);
                        sb.Append(")\\/");
                        sb.Append(ss.Framing);
                        break;
                }    

            };







            if (t == typeof(System.Int16))
            {
                Action<StringBuilder, object,SerializationSettings> f = (sb, p1, ss) =>
                {
                    sb.Append(((System.Int16)p1).ToString());                        
                };

                return f;
            }
            else if (t == typeof(System.Int16?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }
                    
                    sb.Append(((System.Int16)p1).ToString());
                 
                };

                return f;
            }

            if (t == typeof(System.DateTime))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    WritingDateTime(p1, sb, ss);
                };

                return f;
            }
            else if (t == typeof(System.DateTime?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }

                    WritingDateTime(p1, sb, ss);                  
                };

                return f;
            }

            else if (t == typeof(System.UInt16))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                   
                    sb.Append(((System.UInt16)p1).ToString());
                  
                };

                return f;
            }
            else if (t == typeof(System.UInt16?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }
                  
                    sb.Append(((System.UInt16)p1).ToString());
                  
                };

                return f;
            }

            else if (t == typeof(System.Int32))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    
                    sb.Append(((System.Int32)p1));
                    
                };

                return f;
            }
            else if (t == typeof(System.Int32?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }
                    
                    sb.Append(((System.Int32)p1).ToString());
                    
                };

                return f;
            }

            else if (t == typeof(System.UInt32))
            {

                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    
                    sb.Append(((System.UInt32)p1).ToString());
                    
                };

                return f;
            }
            else if (t == typeof(System.UInt32?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }
                    
                    sb.Append(((System.UInt32)p1).ToString());
                    
                };

                return f;
            }


            else if (t == typeof(System.Int64))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    
                    sb.Append(((System.Int64)p1).ToString());
                    
                };

                return f;
            }
            else if (t == typeof(System.Int64?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }
                    
                    sb.Append(((System.Int64)p1).ToString());
                    
                };

                return f;
            }


            else if (t == typeof(System.UInt64))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    
                    sb.Append(((System.UInt64)p1).ToString());
                    
                };

                return f;
            }
            else if (t == typeof(System.UInt64?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }
                    
                    sb.Append(((System.UInt64)p1).ToString());
                    
                };

                return f;
            }


            else if (t == typeof(System.String))
            {               


                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }

                    WritingStringUnsafe(sb, (string)p1, ss);
                    

                };

                return f;
            }

            else if (t == typeof(System.Char))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    WritingStringUnsafe(sb, Convert.ToString(p1), ss);
                    //WritingString(Convert.ToString(p1), sb, ss);
                };

                return f;
            }
            else if (t == typeof(System.Char?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }

                    WritingStringUnsafe(sb, Convert.ToString(p1), ss);
                    //WritingString(Convert.ToString(p1), sb, ss);
                    
                  
                    
                };

                return f;
            }

            else if (t == typeof(double))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    //Use decimal for high precision
                    sb.Append(((double)p1).ToString(CultureInfo.InvariantCulture));                    
                };

                return f;
            }
            else if (t == typeof(double?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }
                    
                    sb.Append(((double)p1).ToString(CultureInfo.InvariantCulture));
                    
                };

                return f;
            }

            else if (t == typeof(float))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    
                    sb.Append(((float)p1).ToString(CultureInfo.InvariantCulture));
                    
                };

                return f;
            }
            else if (t == typeof(float?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }
                    
                    sb.Append(((float)p1).ToString(CultureInfo.InvariantCulture));
                    
                };

                return f;
            }
            else if (t == typeof(decimal))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    
                    sb.Append(((decimal)p1).ToString(CultureInfo.InvariantCulture));
                    
                };

                return f;
            }
            else if (t == typeof(decimal?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }
                    
                    sb.Append(((decimal)p1).ToString(CultureInfo.InvariantCulture));
                    
                };

                return f;
            }

            else if (t == typeof(bool))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {

                    sb.Append((bool)p1 ? ss.TrueIdentifier : ss.FalseIdentifier);
                    
                };

                return f;
            }
            else if (t == typeof(bool?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }
                    
                    sb.Append((bool)p1 ? ss.TrueIdentifier : ss.FalseIdentifier);
                    
                };

                return f;
            }

            else if (t == typeof(byte))
            {               
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    
                    sb.Append(((byte)p1).ToString());
                    
                };

                return f;
            }
            else if (t == typeof(byte?))
            {              
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }
                    
                    sb.Append(((byte)p1).ToString());
                    
                };

                return f;
            }

            else if (t == typeof(sbyte))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    
                    sb.Append(((sbyte)p1).ToString());
                    
                };

                return f;
            }
            else if (t == typeof(sbyte?))
            {            
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }
                    
                    sb.Append(((sbyte)p1).ToString());
                    
                };

                return f;
            }


            else if (t.IsEnum)
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    sb.Append(Convert.ToInt64(p1).ToString());                  
                };

                return f;
            }


            else if (t == typeof(byte[]))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }

                    sb.Append(ss.Framing);                    
                    var bt = (byte[])p1;
                    sb.Append(Convert.ToBase64String(bt, 0, bt.Length, Base64FormattingOptions.None));
                    sb.Append(ss.Framing);
                    
                };

                return f;
            }

            else if (t == typeof(TimeSpan))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    TimeSpan ts = (TimeSpan)p1;
                    sb.Append(ss.Framing);
                    if (ts.Days > 0)
                    {
                        sb.Append(ts.Days);
                        sb.Append(".");
                    }
                    sb.Append(String.Format("{0:D2}", ts.Hours));
                    sb.Append(":");
                    sb.Append(String.Format("{0:D2}", ts.Minutes));
                    sb.Append(":");
                    sb.Append(String.Format("{0:D2}", ts.Seconds));
                    sb.Append(".");
                    sb.Append(String.Format("{0:D3}", ts.Milliseconds));

                    //sb.Append(ts.ToString());

                    sb.Append(ss.Framing);

                };

                return f;
            }
            else if (t == typeof(TimeSpan?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }

                    TimeSpan ts = (TimeSpan)p1;                   
                    sb.Append(ss.Framing);
                    sb.Append(ts.ToString());
                    sb.Append(ss.Framing);

                };

                return f;
            }

            else if (t == typeof(Guid))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    Guid guid = (Guid)p1;
                    //  ts=new TimeSpan(
                    sb.Append(ss.Framing);
                    sb.Append(guid.ToString());
                    sb.Append(ss.Framing);

                };

                return f;
            }
            else if (t == typeof(Guid?))
            {
                Action<StringBuilder, object, SerializationSettings> f = (sb, p1, ss) =>
                {
                    if (p1 == null)
                    {
                        sb.Append(ss.NullIdentifier);
                        return;
                    }

                    Guid guid = (Guid)p1;
                    //  ts=new TimeSpan(
                    sb.Append(ss.Framing);
                    sb.Append(guid.ToString());
                    sb.Append(ss.Framing);

                };

                return f;
            }

            return null;
        }
        #endregion



        /// <summary>
        /// 
        /// </summary>
        /// <param name="hex"></param>
        /// <returns></returns>
        static byte[] StringToByteArray(String hex)
        {
            int NumberChars = hex.Length;
            byte[] bytes = new byte[NumberChars / 2];

            for (int i = 0; i < NumberChars; i += 2)
            {
                bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
            }
            return bytes;
        }


        #region "Type Converter FromString"
        /// <summary>
        /// Key is TypeFullName, Value is converter to string for static types
        /// </summary>
        static Dictionary<string, Func<string, SerializationSettings, Tuple<bool, object>>> dStaticTypeConvertersFromString = new Dictionary<string, Func<string, SerializationSettings, Tuple<bool, object>>>();
        static ReaderWriterLockSlim _sync_dStaticTypeConvertersFromString = new ReaderWriterLockSlim();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static Func<string, SerializationSettings, Tuple<bool, object>> GetFromStringConverterForStaticType(Type t)
        {
            Func<string, SerializationSettings, Tuple<bool, object>> res = null;

            _sync_dStaticTypeConvertersFromString.EnterUpgradeableReadLock();
            try
            {

                string strType = t.ToString();

                if (!dStaticTypeConvertersFromString.TryGetValue(strType, out res))
                {
                    _sync_dStaticTypeConvertersFromString.EnterWriteLock();
                    try
                    {
                        if (!dStaticTypeConvertersFromString.TryGetValue(strType, out res))
                        {
                            res = GetTypeConverterFromString(t);
                            dStaticTypeConvertersFromString[strType] = res;
                        }
                    }
                    finally
                    {
                        _sync_dStaticTypeConvertersFromString.ExitWriteLock();
                    }
                }
            }
            finally
            {
                _sync_dStaticTypeConvertersFromString.ExitUpgradeableReadLock();
            }

            return res;
        }
       






















        /// <summary>
        /// 
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static Func<string, SerializationSettings, Tuple<bool, object>> GetTypeConverterFromString(Type t)
        {
            //!!!!!!!!!!!!!!!!!!!!!!  TO DO IN STRING TYPE DESERIALIZATOR: enum, byte[], datetime UTC/NOT, TIMESPAN, GUID

            

            if(t == typeof(System.Int16))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    Int16 ret = 0;
                    if (Int16.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.Int16?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    System.Int16 ret = 0;
                    if (System.Int16.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            if (t == typeof(System.DateTime))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    DateTime ret = DateTime.Now;

                    if (DateTime.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.DateTime?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    DateTime ret = DateTime.Now;

                    if (DateTime.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(System.UInt16))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    UInt16 ret = 0;
                    if (UInt16.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.UInt16?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    System.UInt16 ret = 0;
                    if (System.UInt16.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(System.Int32))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    System.Int32 ret = 0;

                    if (System.Int32.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.Int32?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if(p1 == null)
                        return new Tuple<bool, object>(true, null);

                    System.Int32 ret = 0;
                    if (System.Int32.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(System.UInt32))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    System.UInt32 ret = 0;
                    if (System.UInt32.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.UInt32?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    System.UInt32 ret = 0;
                    if (System.UInt32.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }


            else if (t == typeof(System.Int64))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    System.Int64 ret = 0;
                    if (System.Int64.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.Int64?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    System.Int64 ret = 0;
                    if (System.Int64.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }


            else if (t == typeof(System.UInt64))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    System.UInt64 ret = 0;
                    if (System.UInt64.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(System.UInt64?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    System.UInt64 ret = 0;
                    if (System.UInt64.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }


            else if (t == typeof(System.String))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    return new Tuple<bool, object>(true, p1);                   
                };

                return f;
            }

            else if (t == typeof(System.Char))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    return new Tuple<bool, object>(true, p1);
                };

                return f;
            }
            else if (t == typeof(System.Char?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    return new Tuple<bool, object>(true, p1);
                };

                return f;
            }

            else if (t == typeof(double))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    double ret = 0;
                    if (Double.TryParse(p1, NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(double?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    double ret = 0;
                    if (Double.TryParse(p1, NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(float))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    float ret = 0;
                    if (float.TryParse(p1, NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(float?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    float ret = 0;
                    if (float.TryParse(p1, NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }


            else if (t == typeof(decimal))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    decimal ret = 0;
                    if (decimal.TryParse(p1, NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(decimal?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    decimal ret = 0;
                    if (decimal.TryParse(p1, NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(bool))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    bool ret = false;
                    if(p1=="1")
                        return new Tuple<bool, object>(true, true);
                    else if(p1 == "0")
                        return new Tuple<bool, object>(true, false);
                    else if (bool.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(bool?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    bool ret = false;
                    if (p1 == "1")
                        return new Tuple<bool, object>(true, true);
                    else if (p1 == "0")
                        return new Tuple<bool, object>(true, false);

                    if (bool.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(byte))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    byte ret = 0;
                    if (byte.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(byte?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    byte ret = 0;
                    if (byte.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t == typeof(sbyte))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    sbyte ret = 0;
                    if (sbyte.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }
            else if (t == typeof(sbyte?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    sbyte ret = 0;
                    if (sbyte.TryParse(p1, out ret))
                        return new Tuple<bool, object>(true, ret);
                    else
                        return new Tuple<bool, object>(false, ret);
                };

                return f;
            }

            else if (t.IsEnum)
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    object ret = Enum.Parse(t, p1, true);
                    return new Tuple<bool, object>(true, ret);
                };

                return f;
            }

            else if (t == typeof(System.Byte[]))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {

                    return new Tuple<bool, object>(true, StringToByteArray(p1));
                };

                return f;
            }

            else if (t == typeof(TimeSpan))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {

                    return new Tuple<bool, object>(true, new TimeSpan());
                };

                return f;
            }

            else if (t == typeof(TimeSpan?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    return new Tuple<bool, object>(true, new TimeSpan());
                };

                return f;
            }

            else if (t == typeof(Guid))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {

                    return new Tuple<bool, object>(true, new Guid());
                };

                return f;
            }

            else if (t == typeof(Guid?))
            {
                Func<string, SerializationSettings, Tuple<bool, object>> f = (p1, ss) =>
                {
                    if (p1 == null)
                        return new Tuple<bool, object>(true, null);

                    return new Tuple<bool, object>(true, new Guid());
                };

                return f;
            }



            return null;
        }

        /*
Int16
Int16?
DateTime
DateTime?
UInt16
UInt16?
Int32
Int32?
UInt32
UInt32?
Int64
Int64?
UInt64
UInt64?
String
Char
Char?
double
double?
float
float?
decimal
decimal?
bool
bool?
byte
byte?
sbyte
sbyte?
IsEnum
byte[]
TimeSpan
TimeSpan?
Guid
Guid?

         */

        #endregion



    }//eoc
}//eon
